home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / ms-0_06.lha / xms-0.06 / Mama.c < prev    next >
C/C++ Source or Header  |  1991-11-12  |  15KB  |  540 lines

  1. /* Mama.c - MandelSpawn master widget */
  2.  
  3. /*  This file is part of MandelSpawn, a parallel Mandelbrot program for
  4.     the X window system.
  5.  
  6.     Copyright (C) 1990, 1991 Andreas Gustafsson
  7.  
  8.     MandelSpawn is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License, version 1,
  10.     as published by the Free Software Foundation.
  11.  
  12.     MandelSpawn is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License,
  18.     version 1, along with this program; if not, write to the Free 
  19.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /* The Mama widget is never realized.  Its purpose is to manage */
  23. /* resources common to all the Ms windows, such as the colormap and */
  24. /* the computation servers.  Now that the computation server interface */
  25. /* has been modularized, Mama has much less to do than before. */
  26.  
  27. /* On some systems, <fcntl.h> may need to be included also */
  28. #include <stdio.h>
  29. #include <errno.h>
  30. extern int errno; /* at least Sony's errno.h misses this */
  31. #include <math.h>
  32.  
  33. #include <X11/IntrinsicP.h>
  34. #include <X11/Xos.h>
  35. #include <X11/StringDefs.h>
  36. #include <X11/Shell.h>
  37.  
  38. #include "backward.h" /* X11R2 backward compatibility stuff */
  39.  
  40. #include "MamaP.h"
  41. #include "Ms.h" /* public header of the child widget */
  42.  
  43.  
  44. /* default timeout in milliseconds per iteration, and constant factor */
  45. #define TIMEOUT_PER_ITER     40    /* this makes 10 s for 250 iters */
  46. #define TIMEOUT_CONST        3000    /* add 3 seconds for network delays */
  47.  
  48.  
  49. /* On the Mach/i386 machines I have tested, floor(0.26) returns -0.5.  Not */
  50. /* good.  Here is a nonportable workaround that's good enough for our */
  51. /* purposes. */
  52. #ifdef BROKEN_FLOOR
  53. #define floor(x) ((double)(long)(x))
  54. #endif
  55.  
  56. extern XtAppContext thisApp;
  57. extern Display *myDisplay;
  58. extern Screen *myScreen;
  59.  
  60. static void Initialize(), ClassInitialize(), Realize(), Destroy(), ReExpose(),
  61.   Resize(), TimeoutCallback();
  62.  
  63. static Boolean SetValues();
  64.  
  65. /* Defaults */
  66.  
  67. /* the width/height defaults are never really used */
  68. static Dimension default_width = 400;
  69. static Dimension default_height = 250;
  70. static int default_colors = 250;
  71. static int default_hues = 250;
  72. static char default_spectrum[] = 
  73.  "blue-aquamarine-cyan-medium sea green-forest green-lime green-\
  74. yellow green-yellow-coral-pink-black";
  75. static Bool default_bw = False;
  76. static Bool default_wrap = False;
  77.  
  78.  
  79. static XtResource resources[] = 
  80. {
  81.   /* Core resources */
  82.   { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  83.       XtOffset(Widget, core.width), XtRDimension, 
  84.       (caddr_t) &default_width },
  85.   { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  86.       XtOffset(Widget, core.height), XtRDimension, 
  87.       (caddr_t) &default_height },
  88.   /* Noncore resources */
  89.   { XtNSpectrum, XtCString, XtRString, sizeof(String),
  90.       XtOffset(MamaWidget, mama.spectrum), XtRString,
  91.       default_spectrum },
  92.   { XtNColours, XtCValue, XtRInt, sizeof(int),
  93.       XtOffset(MamaWidget, mama.n_colours), XtRInt,
  94.       (caddr_t) &default_colors },
  95.   { XtNHues, XtCValue, XtRInt, sizeof(int),
  96.       XtOffset(MamaWidget, mama.n_hues), XtRInt,
  97.       (caddr_t) &default_hues },
  98.   { XtNBw, XtCValue, XtRBool, sizeof(Bool),
  99.       XtOffset(MamaWidget, mama.bw), XtRBool,
  100.       (caddr_t) &default_bw },
  101.   { XtNWrap, XtCValue, XtRBool, sizeof(Bool),
  102.       XtOffset(MamaWidget, mama.wrap), XtRBool,
  103.       (caddr_t) &default_wrap }
  104. };
  105.  
  106.  
  107. MamaClassRec mamaClassRec = 
  108. {   /* core fields */
  109.     { 
  110.     /* superclass        */    &widgetClassRec,
  111.     /* class_name        */    "Mama",
  112.     /* widget_size        */    sizeof(MamaRec),
  113.     /* class_initialize        */      NULL,
  114.     /* class_part_initialize    */    NULL,
  115.     /* class_inited        */    FALSE,
  116.     /* initialize        */    Initialize,
  117.     /* initialize_hook        */    NULL,
  118.     /* realize            */    NULL,
  119.     /* actions            */    NULL,
  120.     /* num_actions        */    0,
  121.     /* resources        */    resources,
  122.     /* resource_count        */    XtNumber(resources),
  123.     /* xrm_class        */    NULL,
  124.     /* compress_motion        */    TRUE,
  125.     /* compress_exposure    */    TRUE,
  126.     /* compress_enterleave    */    TRUE,
  127.     /* visible_interest        */    FALSE,
  128.     /* destroy            */    Destroy,
  129.     /* resize            */    NULL,
  130.     /* expose            */    NULL,
  131.     /* set_values        */    SetValues,
  132.     /* set_values_hook        */    NULL,
  133.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  134.     /* get_values_hook        */    NULL,
  135.     /* accept_focus        */    NULL,
  136.     /* version            */    XtVersion,
  137.     /* callback_private        */    NULL,
  138.     /* tm_table            */    NULL,
  139.     /* query_geometry        */    NULL
  140.     },
  141.     /* noncore fields */
  142.     {
  143.     /* dummy            */    0
  144.     }
  145. };
  146.  
  147. WidgetClass mamaWidgetClass = (WidgetClass) &mamaClassRec;
  148.  
  149.  
  150. /* Set up the colour map */
  151.  
  152. static void 
  153.   MsColourSetup(w)
  154. MamaWidget w;
  155. { unsigned int i;
  156.   unsigned int ncolours;
  157.   unsigned int nhues;
  158.   unsigned int nstops;
  159.   unsigned long *phpixels;
  160.   unsigned long *pixels;
  161.   XColor *stops;
  162.   XColor *colourset;
  163.   unsigned stops_allocated=4; /* initial allocation of colour stops */
  164.   char *p;
  165.   stops=(XColor *) XtMalloc(stops_allocated * sizeof(XColor));
  166.   /* parse the "spectrum" resource */
  167.   p=w->mama.spectrum;
  168.   i=0;
  169.   while(1)
  170.   { char *end;
  171.     XColor dummy;
  172.     end=index(p, '-');
  173.     if(end) *end = '\0';
  174.     if(i >= stops_allocated)
  175.     { stops_allocated *= 2;
  176.       stops=(XColor *)
  177.     XtRealloc((char *) stops, stops_allocated * sizeof(XColor));
  178.     }
  179.     if(! XLookupColor(myDisplay, DefaultColormapOfScreen(myScreen), p,
  180.              &stops[i], &dummy))
  181.     { static char *err = "unrecognized colour in spectrum: ";
  182.       char *msg = XtMalloc(sizeof(err)+strlen(p));
  183.       strcpy(msg, err);
  184.       strcat(msg, p);
  185.       XtAppError(thisApp, msg);
  186.       XtFree(msg); /*NOTREACHED*/
  187.     }
  188.     i++;
  189.     if(end) p=end+1; 
  190.     else break;
  191.   }
  192.   nstops=i;
  193.   ncolours=w->mama.n_colours;
  194.   nhues=w->mama.n_hues;
  195.  
  196.   /* physical pixel mapping (from colour number to pixel value, */
  197.   /* "ncolours" entries) */
  198.   phpixels=
  199.     (unsigned long *) XtMalloc(ncolours * sizeof(unsigned long));
  200.   
  201.   /* logical pixel mapping (from iteration count to pixel value, */
  202.   /* "nhues" entries) */
  203.   pixels=
  204.     (unsigned long *) XtMalloc(nhues * sizeof(unsigned long));
  205.  
  206.   w->mama.my_colormap = DefaultColormapOfScreen(myScreen);
  207.   
  208.   if(! XAllocColorCells(myDisplay, w->mama.my_colormap,
  209.                False, NULL, 0,  
  210.                phpixels, ncolours))
  211.   { /* allocation our of the default colormap failed, so we */
  212.     /* try to allocate one of our own */
  213.     XColor dummy;
  214.     w->mama.my_colormap =
  215.       XCopyColormapAndFree(myDisplay, w->mama.my_colormap);
  216.     if(! w->mama.my_colormap)
  217.       XtAppError(thisApp, "XCopyColormapAndFree failed");
  218. #ifdef MENU
  219.     /* make sure that this colourmap also has black and white pixels */
  220.     /* for use by the popup menu, if any.  Don't care about errors here. */
  221.     (void) XAllocNamedColor(myDisplay, w->mama.my_colormap,
  222.                 "white", &dummy, &dummy);
  223.     (void) XAllocNamedColor(myDisplay, w->mama.my_colormap,
  224.                 "black", &dummy, &dummy);
  225. #endif
  226.     /* retry the allocation */
  227.     if(! XAllocColorCells(myDisplay, w->mama.my_colormap,
  228.               False, NULL, 0,  
  229.               phpixels, ncolours))
  230.     { XtAppError(thisApp,
  231. "too many colours for this screen.  Please specify a smaller number\n\
  232. of colours with the -colours option, or use -bw to run in black and\n\
  233. white.");
  234.     }
  235.   }
  236.  
  237.   colourset=(XColor *) XtMalloc(ncolours * sizeof(XColor));
  238.   for(i=0; i<ncolours; i++)
  239.   { double flstop, stop, fpart;
  240.     int istop, jstop;
  241.     flstop=(double) i / (double) (ncolours-1) * (double) (nstops-1);
  242.     /* calculate the number of the next lower stop */
  243.     /* should be ==nstops-1 only for i==ncolours-1 */
  244.     stop=floor(flstop);
  245.     fpart=flstop-stop;
  246.     /* calculate the indices of the two stops to interpolate between */
  247.     /* If we are at the last stop, interpolate between it and itself */
  248.     /* to avoid accesses past the end of the array (the value will be */
  249.     /* multiplied by zero anyway) */
  250.     istop=(int) stop;
  251.     jstop=(istop+1 >= nstops ? nstops-1 : istop+1);
  252.  
  253.     colourset[i].pixel=phpixels[i];
  254.     colourset[i].red=
  255.       floor((1-fpart)*stops[istop].red + fpart*stops[jstop].red);
  256.     colourset[i].green=
  257.       floor((1-fpart)*stops[istop].green + fpart*stops[jstop].green);
  258.     colourset[i].blue=
  259.       floor((1-fpart)*stops[istop].blue + fpart*stops[jstop].blue);
  260.     colourset[i].flags=DoRed|DoGreen|DoBlue;
  261.   }
  262.  
  263.   if(w->mama.wrap)
  264.   { /* Wrap the spectrum around several times if needed to get the */
  265.     /* desired number of "hues" from a limited number of "colours" */
  266.     for(i=0; i<nhues-1; i++)
  267.     { pixels[i] = phpixels[i % ncolours];
  268.     }
  269.   }
  270.   else
  271.   { /* Don't wrap; give the same colour to several consecutive iteration */
  272.     /* values */
  273.     int divfactor = (nhues + ncolours-1) / ncolours;
  274.     for(i=0; i<nhues-1; i++)
  275.     { pixels[i] = phpixels[i / divfactor];
  276.     }
  277.   }
  278.   /* ...but make sure the last colour is what the user specified. */
  279.   pixels[nhues-1] = phpixels[ncolours-1];
  280.   w->mama.pixels=pixels;
  281.   
  282.   XStoreColors(myDisplay, w->mama.my_colormap, 
  283.            colourset, ncolours);
  284.   XtFree((char *) colourset);
  285. }
  286.  
  287.  
  288. /* Set up for black-and-white operation */
  289.  
  290. static void 
  291.   MsBwSetup(w)
  292. MamaWidget w;
  293. { unsigned long *pixels;
  294.  
  295.   unsigned niter = w->mama.n_hues;
  296.   register int i;
  297.   
  298.   pixels=w->mama.pixels=
  299.     (unsigned long *) XtMalloc(niter * sizeof(unsigned long));
  300.  
  301.   /* Use alternating black/white bands */
  302.   for(i=0; i<niter; i++)
  303.   { pixels[i] = (niter - i) & 0x01 ?
  304.       BlackPixelOfScreen(myScreen) : WhitePixelOfScreen(myScreen);
  305.   }
  306. }
  307.  
  308.  
  309. /* Callback function to be called when data arrives from a slave */
  310.  
  311. void MsSocketInputCallback(client_data, source, id)
  312.      caddr_t client_data; int *source; XtInputId *id;
  313. { MamaWidget w=(MamaWidget) client_data;
  314.   if(*id != w->mama.input_id || *source != wf_socket(w->mama.workforce)) 
  315.   { XtAppError(thisApp, "unexpected input from slave");
  316.   }
  317.   /* this will receive the message and call GotResult with it */
  318.   wf_handle_socket_input(w->mama.workforce, (char *) w);
  319. }
  320.  
  321.  
  322. /* Initialize the widget */
  323. static void
  324. Initialize(request, new)
  325.      MamaWidget request;
  326.      MamaWidget new;
  327. { /* we haven't made any popups yet */
  328.   new->mama.n_popups_created=0;
  329.  
  330.   /* initialize the workforce */
  331.   new->mama.workforce =
  332.     wf_init(new->mama.n_hues * TIMEOUT_PER_ITER + TIMEOUT_CONST);
  333.  
  334.   /* pass a pointer to the master widget as "client data" */
  335.   new->mama.input_id=
  336.     XtAppAddInput(thisApp,
  337.           wf_socket(new->mama.workforce),
  338.           (caddr_t) XtInputReadMask,
  339.           MsSocketInputCallback,
  340.           (caddr_t) new);
  341.  
  342. #ifndef OLD_TIMEOUT
  343.   (void) XtAppAddTimeOut(thisApp, 1000,
  344.           TimeoutCallback, (caddr_t) new->mama.workforce);
  345. #endif
  346.  
  347.   if(new->mama.n_colours > new->mama.n_hues)
  348.   { /* we have more colours than iterations, throw some away */
  349.     new->mama.n_colours = new->mama.n_hues;
  350.   }
  351.   if(new->mama.bw)
  352.     goto force_bw;
  353.  
  354.   /* set new->mama.pixels and the colour map, if applicable */
  355.   switch(DefaultVisualOfScreen(myScreen)->class)
  356.   {
  357.   case PseudoColor:
  358.     MsColourSetup(new); break;
  359.   case StaticGray:
  360.   force_bw:
  361.     MsBwSetup(new); break;
  362.   default:
  363.     XtAppError(thisApp, "unsupported visual type");
  364.   }
  365. }
  366.  
  367.  
  368. /* Provide memory allocation and error handling services to the workforce */
  369. /* package, in a way compatible with Xt */
  370.  
  371. char *wf_alloc(size) unsigned size; { return(XtMalloc(size)); }
  372. char *wf_realloc(p, size) char *p; unsigned size;
  373.   { return(XtRealloc(p, size)); }
  374. void wf_free(p) char *p; { XtFree(p); }
  375.  
  376. void wf_error(msg) char *msg; { XtAppError(thisApp, msg); }
  377. void wf_warn(msg) char *msg; { XtAppWarning(thisApp, msg); }
  378.  
  379.  
  380. #ifndef OLD_TIMEOUT
  381. static void 
  382. TimeoutCallback(client_data, id) 
  383.      caddr_t client_data;
  384.      XtIntervalId *id;
  385. { wf_tick((wf_state *) client_data);
  386.   /* reset the timeout */
  387.   XtAppAddTimeOut(thisApp, 1000,
  388.           TimeoutCallback, client_data);
  389. }
  390.  
  391. #else
  392.  
  393. /* Callback to be called whenever a slave times out */
  394.  
  395. static void 
  396. TimeoutCallback(client_data, id) 
  397.      caddr_t client_data;
  398.      XtIntervalId *id;
  399. { wf_timed_out(client_data);
  400. }
  401.  
  402. char *wf_add_timeout(millisecs, client_data)
  403.   unsigned millisecs; char *client_data;
  404. { return((char *) XtAppAddTimeOut(thisApp, millisecs,
  405.                   TimeoutCallback, (caddr_t) client_data));
  406. }
  407.  
  408. void wf_remove_timeout(id) char *id;
  409. { XtRemoveTimeOut((XtIntervalId *) id);
  410. }
  411. #endif
  412.  
  413.  
  414.  
  415. /* Update widget resources (no changeable resources so far) */
  416.  
  417. static Boolean SetValues(current, request, new)
  418.      MamaWidget current, request, new;
  419. { return(False);
  420. }
  421.  
  422.  
  423. /* Die */
  424.  
  425. void Shutdown(w)
  426.      MamaWidget w;
  427. { XCloseDisplay(XtDisplay(w));
  428.   exit(0);
  429. }
  430.  
  431.  
  432. /* This callback is called whenever a popup child dies */
  433.  
  434. void
  435. PostMortem(w, client_data, call_data)
  436.      MsWidget w;
  437.      caddr_t client_data;
  438.      caddr_t call_data;
  439. { MamaWidget ma=(MamaWidget) client_data;
  440.   /* inform the slave handler that we don't want any more replies */
  441.   wf_client_died(ma->mama.workforce, (char *) w);
  442.   /* If our last child is dying we have nothing to live for; */
  443.   /* commit suicide */
  444.   if(ma->core.num_popups == 1)
  445.     Shutdown(ma);
  446. }
  447.  
  448.  
  449. /* Pop up a new Ms window, making it a child of the Mama. */
  450. /* The caller must make sure there is room in the "shell_args" array */
  451. /* for one more arg. */
  452.  
  453. void PopupAnother (w, shell_args, num_shell_args, args, num_args)
  454.      MamaWidget w;
  455.      ArgList shell_args;
  456.      Cardinal num_shell_args;
  457.      ArgList args;
  458.      Cardinal num_args;
  459. { Widget the_widget;
  460.   Widget the_shell;
  461.   char popup_name[32]; /* unique name for each popup widget */
  462.  
  463.   sprintf(popup_name, "ms_%d", ++w->mama.n_popups_created);
  464.  
  465.   /* make the popup use our colormap */
  466.   XtSetArg(shell_args[num_shell_args], XtNcolormap, w->mama.my_colormap);
  467.   num_shell_args++;
  468.  
  469.   /* this is for OpenWindows... */
  470.   XtSetArg(shell_args[num_shell_args], XtNinput, True);
  471.   num_shell_args++;
  472.  
  473.   the_shell=
  474.     XtCreatePopupShell(popup_name, topLevelShellWidgetClass, w, 
  475.                shell_args, num_shell_args);
  476.   
  477.   the_widget=XtCreateManagedWidget("view",
  478.                    (WidgetClass) msWidgetClass,
  479.                    (Widget) the_shell, 
  480.                    args, num_args);
  481.   XtAddCallback(the_widget, XtNdestroyCallback, PostMortem, (caddr_t) w);
  482.         
  483.   XtPopup(the_shell, XtGrabNone);
  484. }
  485.  
  486.  
  487. /* Destroy the widget */
  488.  
  489. static void
  490. Destroy (w)
  491.   MamaWidget w;
  492. {
  493. }
  494.  
  495.  
  496. /* The Ms widget needs to know the maximums message size, */
  497. /* how may colours there are, etc.  Make that information */
  498. /* available through public functions */
  499.  
  500. unsigned 
  501. MaxIterations(w)
  502.      MamaWidget w;
  503. { return(w->mama.n_hues);
  504. }
  505.  
  506. unsigned MamaHeight(w)
  507.      MamaWidget w;
  508. { return(w->core.height);
  509. }
  510.  
  511. unsigned MamaWidth(w)
  512.      MamaWidget w;
  513. { return(w->core.width);
  514. }
  515.  
  516. unsigned 
  517. MamaColormap(w)
  518.      MamaWidget w;
  519. { return(w->mama.my_colormap);
  520. }
  521.  
  522. wf_state *MamaWorkforce(w)
  523.      MamaWidget w;
  524. { return(w->mama.workforce);
  525. }
  526.  
  527. unsigned long *
  528. MamaPixels(w)
  529.      MamaWidget w;
  530. { return(w->mama.pixels);
  531. }
  532.  
  533. /* Print some performance statistics about the slaves */
  534.  
  535. void SlaveStatistics(w)
  536.      MamaWidget w;
  537. { wf_print_stats(w->mama.workforce, stdout);
  538. }
  539.  
  540.